// 文件路径: dbms/execution/execution/SeqScanExecutor.java
package com.dbms.execution.execution;

import com.dbms.catalog.Catalog;
import com.dbms.common.Schema;
import com.dbms.common.Tuple;
import com.dbms.execution.plan.PlanNode;
import com.dbms.storage.BufferPoolManager;
import com.dbms.storage.Page;
import com.dbms.storage.TablePage;

import java.io.IOException;

/**
 * SeqScanExecutor (顺序扫描执行器) 实现了最基本的数据访问方法：全表扫描。
 * 它从表的第一个页面开始，逐个页面、逐个槽位地读取所有元组，直到表的末尾。
 * 这是处理没有合适索引的查询的基础。
 * 【已修改】这个版本集成了用于 EXPLAIN ANALYZE 的计时和计数功能。
 */
public class SeqScanExecutor implements Executor {

    private final BufferPoolManager bufferPoolManager;
    private final Catalog.TableMetadata tableInfo;
    private final Schema schema;

    // 迭代器状态变量
    private int currentPageId;  // 当前正在扫描的页面的 ID
    private int currentSlotNum; // 当前页面中下一个要检查的槽位号
    private Page currentPage;   // 当前正持有锁和 pin 的页面对象

    // 【修改】用于 EXPLAIN ANALYZE 的性能指标变量
    private long startTimeNanos; // 开始执行的时间戳（纳秒）
    private long totalTimeNanos; // 总耗时（纳秒）
    private long rowsProduced;   // 产出的总行数

    public SeqScanExecutor(BufferPoolManager bpm, Catalog catalog, String tableName) {
        this.bufferPoolManager = bpm;
        this.tableInfo = catalog.getTable(tableName);
        if (this.tableInfo == null) {
            throw new IllegalArgumentException("Table not found: " + tableName);
        }
        this.schema = tableInfo.schema;
    }

    @Override
    public void open() {
        // 初始化扫描状态，从表的根页面开始
        this.currentPageId = tableInfo.rootPageId;
        this.currentSlotNum = 0;
        this.currentPage = null;
        this.rowsProduced = 0;
        // 【修改】使用更高精度的 System.nanoTime() 记录开始时间
        this.startTimeNanos = System.nanoTime();
    }

    @Override
    public Tuple next() {
        try {
            while (true) {
                // 如果当前没有持有的页面，则需要获取一个新页面
                if (currentPage == null) {
                    if (currentPageId == TablePage.INVALID_PAGE_ID) {
                        // 如果页面 ID 无效，说明已经到达表链表的末尾
                        return null;
                    }
                    // 从缓冲池中获取页面
                    currentPage = bufferPoolManager.fetchPage(currentPageId);
                    if (currentPage == null) return null; // 获取失败
                    currentPage.rLock(); // 加读锁
                    this.currentSlotNum = 0; // 重置槽位号
                }

                TablePage currentPageView = new TablePage(currentPage);
                // 遍历当前页面的所有槽位
                while (currentSlotNum < currentPageView.getSlotCount()) {
                    byte[] tupleData = currentPageView.getTuple(currentSlotNum);
                    currentSlotNum++;
                    if (tupleData != null) {
                        // 如果槽位中有有效数据，则反序列化为元组并返回
                        this.rowsProduced++;
                        return new Tuple(tupleData, this.schema);
                    }
                }

                // 当前页面已扫描完毕，准备移动到下一个页面
                int nextPageId = currentPageView.getNextPageId();
                currentPage.rUnlock(); // 释放当前页的锁
                bufferPoolManager.unpinPage(currentPage.getPageId(), false); // 解钉当前页
                currentPage = null; // 清空当前页引用
                currentPageId = nextPageId; // 更新页面ID为下一页
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void close() {
        // 【修改】计算纳秒级的总耗时
        this.totalTimeNanos = System.nanoTime() - startTimeNanos;
        // 确保如果扫描中途结束，持有的页面资源能被正确释放
        if (currentPage != null) {
            currentPage.rUnlock();
            bufferPoolManager.unpinPage(currentPage.getPageId(), false);
            currentPage = null;
        }
        // 重置状态
        this.currentPageId = TablePage.INVALID_PAGE_ID;
        this.currentSlotNum = 0;
    }

    @Override
    public Schema getSchema() {
        return this.schema;
    }

    @Override
    public PlanNode getPlanNode() {
        // 为 EXPLAIN ANALYZE 创建计划节点
        PlanNode node = new PlanNode("Sequential Scan", "on table '" + tableInfo.tableName + "'");
        // 【修改】设置从性能指标中收集到的纳秒级执行时间和产出行数
        node.setExecutionTimeNanos(this.totalTimeNanos);
        node.setRowsProduced(this.rowsProduced);
        return node;
    }
}